using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using OracleInternal.Json.Common;
using OracleInternal.Json.Sql;

namespace OracleInternal.Json.Binary
{
	internal class OsonObject : OsonAbstractObject, IOracleJsonObject, IOracleJsonStructure, IOracleJsonValue, IDictionary<string, OracleJsonValue>, ICollection<KeyValuePair<string, OracleJsonValue>>, IEnumerable<KeyValuePair<string, OracleJsonValue>>, IEnumerable, IEnumerator<KeyValuePair<string, OracleJsonValue>>, IEnumerator, IDisposable
	{
		private int m_iter = -1;

		public int Count => m_size;

		public bool IsReadOnly => false;

		public OracleJsonValue this[string key]
		{
			get
			{
				return (OracleJsonValue)GetInternal(key);
			}
			set
			{
				throw CreateNotModifiable();
			}
		}

		public ICollection<string> Keys
		{
			get
			{
				throw CreateNotModifiable();
			}
		}

		public ICollection<OracleJsonValue> Values
		{
			get
			{
				throw CreateNotModifiable();
			}
		}

		public KeyValuePair<string, OracleJsonValue> Current
		{
			get
			{
				string fieldName = GetFieldName(m_iter);
				OracleJsonValue value = (OracleJsonValue)GetValueInternal(GetChildOffset(m_iter));
				return new KeyValuePair<string, OracleJsonValue>(fieldName, value);
			}
		}

		object IEnumerator.Current
		{
			get
			{
				string fieldName = GetFieldName(m_iter);
				OracleJsonValue value = (OracleJsonValue)GetValueInternal(GetChildOffset(m_iter));
				return new KeyValuePair<string, OracleJsonValue>(fieldName, value);
			}
		}

		internal OsonObject(OsonContext ctx, int pos)
			: base(ctx)
		{
			Init(pos);
		}

		internal OracleJsonValue Get(object key)
		{
			return (OracleJsonValue)GetInternal(key);
		}

		public override string ToJsonString()
		{
			StringWriter stringWriter = new StringWriter();
			OracleJsonSerializer oracleJsonSerializer = new OracleJsonSerializer(stringWriter);
			oracleJsonSerializer.Write(this);
			oracleJsonSerializer.Close();
			return stringWriter.ToString();
		}

		internal byte[] GetBytes(string key)
		{
			int childOffset = GetChildOffset(key);
			if (childOffset == -1)
			{
				throw new NullReferenceException();
			}
			return ((OracleJsonBinary)GetValueInternal(childOffset)).GetBytes();
		}

		internal byte[] GetBytes(string key, byte[] d)
		{
			int childOffset = GetChildOffset(key);
			if (childOffset == -1)
			{
				return d;
			}
			OracleJsonValue oracleJsonValue = (OracleJsonValue)GetValueInternal(childOffset);
			if (oracleJsonValue.GetOracleJsonType() != OracleJsonType.BINARY)
			{
				return d;
			}
			return oracleJsonValue.AsJsonBinary().GetBytes();
		}

		internal double GetDouble(string key)
		{
			int childOffset = GetChildOffset(key);
			if (childOffset == -1)
			{
				throw new NullReferenceException();
			}
			return ((OracleJsonNumber)GetValueInternal(childOffset)).DoubleValue();
		}

		internal double GetDouble(string key, double d)
		{
			int childOffset = GetChildOffset(key);
			if (childOffset == -1)
			{
				return d;
			}
			return GetNumeric(childOffset)?.DoubleValue() ?? d;
		}

		private OracleJsonNumber GetNumeric(int childOffset)
		{
			object valueInternal = GetValueInternal(childOffset);
			if (!(valueInternal is OracleJsonNumber))
			{
				return null;
			}
			return (OracleJsonNumber)valueInternal;
		}

		internal long GetLong(string key, long d)
		{
			int childOffset = GetChildOffset(key);
			if (childOffset == -1)
			{
				return d;
			}
			return GetNumeric(childOffset)?.LongValue() ?? d;
		}

		internal decimal GetBigDecimal(string key, decimal d)
		{
			int childOffset = GetChildOffset(key);
			if (childOffset == -1)
			{
				return d;
			}
			return GetNumeric(childOffset)?.BigDecimalValue() ?? d;
		}

		internal long GetLong(string key)
		{
			int childOffset = GetChildOffset(key);
			if (childOffset == -1)
			{
				throw new NullReferenceException();
			}
			return ((OracleJsonNumber)GetValueInternal(childOffset)).LongValue();
		}

		internal decimal GetBigDecimal(string key)
		{
			int childOffset = GetChildOffset(key);
			if (childOffset == -1)
			{
				throw new NullReferenceException();
			}
			return ((OracleJsonNumber)GetValueInternal(childOffset)).BigDecimalValue();
		}

		internal DateTime GetDateTime(string key)
		{
			int childOffset = GetChildOffset(key);
			if (childOffset == -1)
			{
				throw new NullReferenceException();
			}
			OracleJsonValue oracleJsonValue = (OracleJsonValue)GetValueInternal(childOffset);
			if (oracleJsonValue.GetOracleJsonType() == OracleJsonType.DATE)
			{
				return ((OracleJsonDate)oracleJsonValue).GetDateTime();
			}
			return ((OracleJsonTimestamp)oracleJsonValue).GetDateTime();
		}

		internal DateTime GetDateTime(string key, DateTime defaultValue)
		{
			int childOffset = GetChildOffset(key);
			if (childOffset == -1)
			{
				return defaultValue;
			}
			OracleJsonValue oracleJsonValue = (OracleJsonValue)GetValueInternal(childOffset);
			if (oracleJsonValue.GetOracleJsonType() == OracleJsonType.DATE)
			{
				return ((OracleJsonDate)oracleJsonValue).GetDateTime();
			}
			if (oracleJsonValue.GetOracleJsonType() == OracleJsonType.TIMESTAMP)
			{
				return ((OracleJsonTimestamp)oracleJsonValue).GetDateTime();
			}
			return defaultValue;
		}

		internal OracleJsonValue Put(string name, string value)
		{
			throw CreateNotModifiable();
		}

		internal OracleJsonValue Put(string name, int value)
		{
			throw CreateNotModifiable();
		}

		internal OracleJsonValue Put(string name, long value)
		{
			throw CreateNotModifiable();
		}

		internal OracleJsonValue PPt(string name, decimal value)
		{
			throw CreateNotModifiable();
		}

		internal OracleJsonValue Put(string name, double value)
		{
			throw CreateNotModifiable();
		}

		internal OracleJsonValue Put(string name, bool value)
		{
			throw CreateNotModifiable();
		}

		internal OracleJsonValue PutNull(string name)
		{
			throw CreateNotModifiable();
		}

		internal OracleJsonValue Put(string name, DateTime defaultValue)
		{
			throw CreateNotModifiable();
		}

		internal OracleJsonValue Put(string name, byte[] values)
		{
			throw CreateNotModifiable();
		}

		internal OracleJsonValue Put(string key, OracleJsonValue value)
		{
			throw CreateNotModifiable();
		}

		internal OracleJsonValue Remove(object key)
		{
			throw CreateNotModifiable();
		}

		private NotSupportedException CreateNotModifiable()
		{
			throw OracleJsonExceptions.OBJ_NOT_MUTABLE.Create(OracleJsonExceptions.ORACLE_FACTORY);
		}

		public void Add(string key, OracleJsonValue item)
		{
			throw CreateNotModifiable();
		}

		public void Clear()
		{
			throw CreateNotModifiable();
		}

		public bool ContainsKey(string key)
		{
			if (key != null)
			{
				return GetChildOffset(key) != -1;
			}
			return false;
		}

		public bool TryGetValue(string key, out OracleJsonValue value)
		{
			OracleJsonValue oracleJsonValue = (OracleJsonValue)GetInternal(key);
			if (oracleJsonValue != null)
			{
				value = oracleJsonValue;
				return true;
			}
			value = null;
			return false;
		}

		public void CopyTo(KeyValuePair<string, OracleJsonValue>[] array, int arrayIndex)
		{
			throw CreateNotModifiable();
		}

		public bool Remove(string key)
		{
			throw CreateNotModifiable();
		}

		public void Add(KeyValuePair<string, OracleJsonValue> item)
		{
			throw CreateNotModifiable();
		}

		public bool Remove(KeyValuePair<string, OracleJsonValue> item)
		{
			throw CreateNotModifiable();
		}

		public bool Contains(KeyValuePair<string, OracleJsonValue> item)
		{
			throw CreateNotModifiable();
		}

		IEnumerator<KeyValuePair<string, OracleJsonValue>> IEnumerable<KeyValuePair<string, OracleJsonValue>>.GetEnumerator()
		{
			return this;
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return this;
		}

		public void Dispose()
		{
		}

		public bool MoveNext()
		{
			if (m_iter < m_size - 1)
			{
				m_iter++;
				return true;
			}
			return false;
		}

		public void Reset()
		{
			m_iter = -1;
		}
	}
}
